package com.zeng.createmd.restfulmodule.util;

import com.zeng.createmd.restfulmodule.itemCache.ItemCache;
import com.zeng.createmd.servicemodule.vo.ItemVo;
import com.zeng.plugin.entity.MenuView;
import com.zeng.plugin.util.FreeMarkUtil;
import com.zeng.plugin.util.HumpStringUtil;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

public class VueUtil {

    File root;

    ItemVo currentItem = ItemCache.currentItem;

    Map<String, MenuView> menuViews;

    public VueUtil(String path) {
        root = new File(path);
    }

    public VueUtil() {

        if (currentItem == null) {
            throw new RuntimeException("没有选择项目");
        }

        String artifactId = (String) currentItem.getInfo().get("artifactId");
        root = new File(currentItem.getPath(), "client/" + artifactId);
        if (!root.exists()) {
            throw new RuntimeException("前端项目尚未初始化");
        }
        this.menuViews = new ProjectUtil().getMenuViews();
        if (this.menuViews == null) {
            this.menuViews = new HashMap<>();
        }
    }

    public void createPackageJSON() {
        List<String> tempalate = new ArrayList<>();
        tempalate.add("vue/package.json");
        try {
            FreeMarkUtil freeMarkUtil = new FreeMarkUtil(tempalate);
            Map<String, Object> data = new HashMap<>();
            data.put("artifactId", currentItem.getInfo().get("artifactId"));
            File file = new File(root, "package.json");
            freeMarkUtil.parse(tempalate.get(0), file, data);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void createView() {
        File viewPath = new File(root, "src/project/view");
        if (!viewPath.exists()) {
            viewPath.mkdirs();
        }
        ProjectUtil projectUtil = new ProjectUtil();
        Map<String, MenuView> menuViews = projectUtil.getMenuViews();
        for (String s : menuViews.keySet()) {
            MenuView menuView = menuViews.get(s);
            String tableName = menuView.getTableName();
            File tableView = new File(viewPath, tableName);
            if (!tableView.exists()) {
                tableView.mkdirs();
            }
            createView(tableView);
            createViewConfig(menuView, tableView);
        }
    }

    public void createConfig() {
        File configPath = new File(root, "src/project/config");
        createApi(configPath);
        createRouter(configPath);
    }

    private void createRouter(File parent) {

        Collection<MenuView> menuViews = this.menuViews.values();
        List<String> tableClassName = menuViews.stream().map(MenuView::getTableName).collect(Collectors.toList());

        List<String> template = new ArrayList<>();
        template.add("config/router");
        try {
            FreeMarkUtil freeMarkUtil = new FreeMarkUtil(template);
            File file = new File(parent, "router.js");
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            if (file.exists()) {
                return;
            }
            Map<String, Object> data = new HashMap<>();
            data.put("tableNames", tableClassName);
            freeMarkUtil.parse(template.get(0), file, data);

        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }

    }

    private void createApi(File parent) {

        List<Map<String, Object>> apis = new ArrayList<>();
        for (String s : this.menuViews.keySet()) {
            Map<String, Object> temp = new HashMap<>();
            temp.put("tableName", HumpStringUtil.humpStringHandle(this.menuViews.get(s).getTableName(), "_"));
            temp.put("add", "add");
            temp.put("delete", "delete");
            temp.put("update", "update");
            temp.put("batchDelete", "batchDelete");
            if (withFile(menuViews.get(s))) {
                temp.put("add", "addWithFile");
                temp.put("delete", "deleteWithFile");
                temp.put("update", "updateWithFile");
                temp.put("batchDelete", "batchDeleteWithFile");
            }
            apis.add(temp);
        }

        List<String> template = new ArrayList<>();
        template.add("config/api");
        try {
            FreeMarkUtil freeMarkUtil = new FreeMarkUtil(template);
            File file = new File(parent, "api.js");
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            if (file.exists()) {
                return;
            }
            Map<String, Object> data = new HashMap<>();
            data.put("apis", apis);
            freeMarkUtil.parse(template.get(0), file, data);

        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    private void createViewConfig(MenuView menuView, File parent) {
        List<String> tempalate = new ArrayList<>();
        tempalate.add("view/config");
        try {
            FreeMarkUtil freeMarkUtil = new FreeMarkUtil(tempalate);
            Map<String, Object> data = new HashMap<>();
            data.put("listTables", handleMenuViewToListTables(menuView));
            data.put("tableName", StringUtil.uncapFirst(HumpStringUtil.humpStringHandle(menuView.getTableName(), "_")));
            data.put("searchView", handleMenuViewToSearchView(menuView));
            data.put("formView", handleMenuViewToFormView(menuView));
            data.put("img", handleImg(menuView));
            data.put("withFile", withFile(menuView) ? 1 : 0);
            File file = new File(parent, "config.js");
            if (file.exists()) {
                return;
            }
            freeMarkUtil.parse(tempalate.get(0), file, data);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void createView(File parent) {
        List<String> resourceList = new ArrayList<>();
        resourceList.add("view/Add.vue");
        resourceList.add("view/Edit.vue");
        resourceList.add("view/List.vue");
        for (String s : resourceList) {
            InputStream resourceAsStream = VueUtil.class.getClassLoader().getResourceAsStream(s);
            FileOutputStream output = null;
            try {
                output = new FileOutputStream(new File(parent, s.split("/")[1]));
                IOUtils.copy(resourceAsStream, output);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                CloseUtil.close(resourceAsStream);
                CloseUtil.close(output);
            }
        }
    }

    private List<Map<String, Object>> handleMenuViewToListTables(MenuView menuView) {
        Map<String, Object> list = menuView.getList();
        String pictureProperty = menuView.getPictureProperty();
        List<String> properties = (List<String>) list.get("properties");
        Map<String, Object> propertyMap = (Map<String, Object>) list.get("propertyMap");
        List<Map<String, Object>> returnValue = new ArrayList<>();
        for (String property : properties) {
            Map<String, Object> temp = new HashMap<>();
            temp.put("prop", property);
            temp.put("label", propertyMap.get(property));
            temp.put("image", 0);
            temp.put("formatter", 0);
            if (property.equals(pictureProperty)) {
                temp.put("image", 1);
            }
            if (propertyIsDate(property, menuView.getTableName())) {
                temp.put("formatter", "function(value) {\n" +
                        "        if (value) {\n" +
                        "          return new Date(value).toLocaleString()\n" +
                        "        }\n" +
                        "        return ''\n" +
                        "      }");
            }
            returnValue.add(temp);
        }
        return returnValue;
    }

    private boolean propertyIsDate(String property, String tableName) {
        if (property.equals("insertDate") || property.equals("updateDate")) {
            return true;
        }
        ProjectUtil projectUtil = new ProjectUtil();
        Map<String, Object> data = projectUtil.getData();
        Map<String, Object> tableMap = (Map<String, Object>) data.get("tableMap");
        Map<String, Object> stringObjectMap = (Map<String, Object>) tableMap.get(tableName);
        List<Map<String, Object>> fields = (List<Map<String, Object>>) stringObjectMap.get("fields");
        for (Map<String, Object> field : fields) {
            String fieldName = (String) field.get("fieldName");
            String type = (String) field.get("type");
            if (fieldName.equals(property)) {
                if (type.equals("Date")) {
                    return true;
                }
            }
        }
        return false;
    }

    private List<Map<String, Object>> handleMenuViewToSearchView(MenuView menuView) {
        Map<String, Object> list = menuView.getList();
        List<String> searchProperties = menuView.getLikeProperty();
        Map<String, Object> propertyMap = (Map<String, Object>) list.get("propertyMap");
        List<Map<String, Object>> returnValue = new ArrayList<>();
        for (String property : searchProperties) {
            Map<String, Object> temp = new HashMap<>();
            temp.put("model", property);
            temp.put("label", propertyMap.get(property));
            returnValue.add(temp);
        }
        return returnValue;
    }

    private List<Map<String, Object>> handleMenuViewToFormView(MenuView menuView) {
        Map<String, Object> edit = menuView.getEdit();
        List<String> properties = (List<String>) edit.get("properties");
        Map<String, Object> propertyMap = (Map<String, Object>) edit.get("propertyMap");
        Map<String, Object> propertyFromMap = (Map<String, Object>) edit.get("propertyFromMap");
        Map<String, Object> propertyMessageMap = (Map<String, Object>) edit.get("propertyMessageMap");
        List<Map<String, Object>> returnValue = new ArrayList<>();
        for (String property : properties) {
            Map<String, Object> temp = new HashMap<>();
            Object type = propertyFromMap.get(property);
            temp.put("type", type);
            temp.put("model", property);
            temp.put("label", propertyMap.get(property));
            temp.put("message", "");
            if (StringUtils.isNotEmpty((String) propertyMessageMap.get(property))) {
                temp.put("message", propertyMessageMap.get(property));
            }
            if (((String) type).contains("upload")) {
                temp.put("model", "file");
            }
            returnValue.add(temp);
        }
        return returnValue;
    }

    private String handleImg(MenuView menuView) {
        Map<String, Object> edit = menuView.getEdit();
        List<String> properties = (List<String>) edit.get("properties");
        Map<String, Object> propertyFromMap = (Map<String, Object>) edit.get("propertyFromMap");
        for (String property : properties) {
            Map<String, Object> temp = new HashMap<>();
            Object value = propertyFromMap.get(property);
            temp.put("type", value);
            if ("upload_2".equals(value)) {
                return property;
            }
        }
        return "";
    }

    private boolean withFile(MenuView menuView) {
        Map<String, Object> edit = menuView.getEdit();
        List<String> properties = (List<String>) edit.get("properties");
        Map<String, Object> propertyFromMap = (Map<String, Object>) edit.get("propertyFromMap");
        for (String property : properties) {
            Map<String, Object> temp = new HashMap<>();
            Object value = propertyFromMap.get(property);
            temp.put("type", value);
            if (((String) value).contains("upload")) {
                return true;
            }
        }
        return false;
    }
}
